package graphics;

import constants.Colors;
import constants.Difficulties;
import constants.Races;
import data.Map;
import data.Player;
import data.Tile;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;

import static constants.Difficulties.values;

/**
 * Panel to handle starting up the game
 *
 * @author Jared Moore
 * @date 10/5/13
 */
public class MainMenuButtonPanel extends JPanel {
	private Map map;
	private MainMenuPanel upperPanel;

	/**
	 * Constructor
	 * Builds this panel with original options
	 */
	public MainMenuButtonPanel(final MainMenuPanel upperPanel) {
		this.upperPanel = upperPanel;
		try {
			UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
		} catch (ClassNotFoundException | InstantiationException
				| IllegalAccessException | UnsupportedLookAndFeelException e) {
			System.err.println("You have an issue with your system");
			e.printStackTrace();
			System.exit(1);
			//if one of these errors are thrown, there is a significant problem with your computer
			//your computer either cannot tell how it formats windows or it cannot use its own theme
			//I like to do this because it gives the panel the look of my system.  Which is much cooler than
			//normal swing stuff
		}

		setLayout(new GridLayout(4, 1));
		JButton newGameButton = new JButton("New Game");
		newGameButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent actionEvent) {
				newGame();
			}
		});
		JButton loadGameButton = new JButton("Load Game");
		loadGameButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent actionEvent) {
				loadGame();
			}
		});
		JButton highScoreButton = new JButton("High Scores");
		highScoreButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent actionEvent) {
				highScores();
			}
		});
		JButton creditsButton = new JButton("Credits");
		creditsButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent actionEvent) {
				credits();
			}
		});
		add(newGameButton);
		add(loadGameButton);
		add(highScoreButton);
		add(creditsButton);
		upperPanel.repaint();
	}

	/**
	 * Gives the user options to set up a new game
	 */
	private void newGame() {
		removeAll();
		upperPanel.setLabelText("M.U.L.E - New Game");
		setLayout(new GridLayout(4, 2));

		JLabel difficultyLabel = new JLabel("Select Difficulty:");
		add(difficultyLabel);

		final JComboBox<Difficulties> difficultyBox = new JComboBox<>(values());
		difficultyBox.setSelectedIndex(0);
		add(difficultyBox);

		JLabel mapTypeLabel = new JLabel("Select Map Type");
		add(mapTypeLabel);

		String[] mapTypes = {"Standard", "Random"};
		final JComboBox mapBox = new JComboBox<>(mapTypes);
		mapBox.setSelectedIndex(0);
		add(mapBox);

		JLabel playerNumberLabel = new JLabel("Number of Players");
		add(playerNumberLabel);

		Integer[] playerNumbers = {2, 3, 4};
		final JComboBox playerNumberBox = new JComboBox<>(playerNumbers);
		mapBox.setSelectedIndex(0);
		add(playerNumberBox);

		JButton backButton = new JButton("Back");
		backButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent actionEvent) {
				upperPanel.removeAll();
				upperPanel.add(new MainMenuButtonPanel(upperPanel));
			}
		});
		add(backButton);

		JButton continueButton = new JButton("Continue");
		continueButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent actionEvent) {
				boolean isRandom;
				isRandom = mapBox.getSelectedIndex() != 0;
				map = new Map((Difficulties) difficultyBox.getSelectedItem(), isRandom,
						(int) playerNumberBox.getSelectedItem());
				setPlayerInformation(1);
			}
		});
		add(continueButton);


		repaint();
	}

	public void loadGame() {
		try {
			ObjectInputStream input = new ObjectInputStream(new FileInputStream("game.ser"));
			map = (Map) input.readObject();
			upperPanel.getFrame().remove(upperPanel);
			upperPanel.getFrame().setContentPane(new OuterPanel(map, true));

		} catch (FileNotFoundException e) {
			JOptionPane.showMessageDialog(this, "There is no file to load, play this game first",
					"Error", JOptionPane.ERROR_MESSAGE);

		} catch (ClassNotFoundException e) {
			JOptionPane.showMessageDialog(this, "The save file was not generated by this program, " +
					"please play this game and go through at least one turn", "Error", JOptionPane.ERROR_MESSAGE);

		} catch (IOException e) {
			System.err.print("You do not have read access on this directory");
			System.exit(1);
		}
		for (Player i : map.getPlayers()) {
			i.setIcon();
		}
		for (Tile[] i : map.getMap()) {
			for (Tile j : i) {
				j.setIcon();
			}
		}
	}

	public void highScores() {
		removeAll();
		upperPanel.setLabelText("M.U.L.E - High Scores");
		//TODO:  Not yet implemented
	}

	public void credits() {
		removeAll();
		upperPanel.setLabelText("M.U.L.E - Credits");
		setLayout(new GridLayout(5, 2));

		JLabel brettLabel = new JLabel("Brett Garcia");
		add(brettLabel);

		JLabel devLabel = new JLabel("Group Member");
		add(devLabel);

		JLabel chrisLabel = new JLabel("Chris Gordon");
		add(chrisLabel);

		JLabel devLabel2 = new JLabel("Developer");
		add(devLabel2);

		JLabel ivanLabel = new JLabel("Ivan Jimenez");
		add(ivanLabel);

		JLabel devLabel3 = new JLabel("Group Member");
		add(devLabel3);

		JLabel jaredLabel = new JLabel("Jared Moore");
		add(jaredLabel);

		JLabel devLabel4 = new JLabel("Developer");
		add(devLabel4);

		JButton button = new JButton("Back");
		button.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent actionEvent) {
				upperPanel.remove(MainMenuButtonPanel.this);
				upperPanel.add(new MainMenuButtonPanel(upperPanel));
				upperPanel.setLabelText("M.U.L.E");
				upperPanel.repaint();
			}
		});
		add(button);
	}

	/**
	 * Step after setting up the game settings
	 * <p/>
	 * precondition: The first step after pressing new game has been completed
	 */
	private void setPlayerInformation(final int currentPlayer) {
		removeAll();
		upperPanel.setLabelText(String.format("M.U.L.E - Player %d Configuration", currentPlayer));

		JLabel nameLabel = new JLabel("Please Enter Your Name");
		add(nameLabel);

		final JTextField nameField = new JTextField();
		nameField.setEditable(true);
		add(nameField);

		JLabel raceLabel = new JLabel("Select Your Desired Race");
		add(raceLabel);

		final JComboBox raceBox = new JComboBox<>(Races.values());
		raceBox.setSelectedIndex(0);
		add(raceBox);

		JLabel colorLabel = new JLabel("Select Your Color");
		add(colorLabel);

		final JComboBox colorBox = new JComboBox<>(map.getAvailableColors().toArray());
		colorBox.setSelectedIndex(0);
		add(colorBox);

		JButton backButton = new JButton("Back");
		backButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent actionEvent) {
				newGame();
				//TODO:  Consider keeping the data that has already been set
				//JComboBox is silly about setting the initial value though
			}
		});
		add(backButton);

		JButton continueButton = new JButton
				(map.getPlayers().length - 1 == currentPlayer ? "Continue" : "Start Game");
		continueButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent actionEvent) {
				if (null == nameField.getText() || nameField.getText().equals("")) {
					JOptionPane.showMessageDialog(upperPanel, "You must enter a name", "Error",
							JOptionPane.PLAIN_MESSAGE);
					return;
				}
				if (map.buildPlayer(nameField.getText(), (Races) raceBox.getSelectedItem(),
						(Colors) colorBox.getSelectedItem())) {
					setPlayerInformation(currentPlayer + 1);
				} else {
					startGame();
				}
			}
		});
		add(continueButton);

		repaint();
	}

	/**
	 * Removes everything from the frame and prepares to start the game
	 */
	private void startGame() {
		upperPanel.getFrame().remove(upperPanel);
		upperPanel.getFrame().setContentPane(new OuterPanel(map, false));
	}
}
